package org.ymh.unix_file_system.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.ymh.unix_file_system.domain.FileSystemError;
import org.ymh.unix_file_system.domain.GlobalVariable;
import org.ymh.unix_file_system.domain.INode;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;

/**
 * @author lenovo
 * @version 1.0
 * @description: 索引的相关操作
 * @date 2023/12/17 15:08
 */
@Repository
public class IndexOperate {
    @Autowired
    private FileSystemError error;
    @Autowired
    private GlobalVariable globalVariable;
    @Autowired
    private JsonDataOperate jsonDataOperate;
    @Autowired
    private FreeBlockLinkedListOperate freeBlockLinkedListOperate;
    /**
    * @Description 指定i节点，获取数据所占物理块，以及索引占的物理块
    * @Author  lenovo
    * @Date   2023/12/17 15:35
    * @Param
    * @Return HashMap {"data":数据物理块,"index":索引物理块}
    * @Exception
    */

    public HashMap<String, LinkedList<Integer>> getOccupyBlockByInode(INode inode)
    {
        HashMap<String, LinkedList<Integer>> map = new HashMap<>();
        map.put("data",null);
        map.put("index",null);
        if(inode.getType()==0)//普通文本
        {
            int kb=inode.getFileLength();
            LinkedList<Integer> data = new LinkedList<>();
            LinkedList<Integer> index = new LinkedList<>();
            //计算索引
            if(kb<=13)
            {
                for (int i = 0; i < kb; i++) {
                    data.add((int) inode.getAddress()[i]);
                }
                map.put("data",data);
            }
            else if(kb<=268)//直接索引x12+一级索引x1
            {
                for (int i = 0; i < 12; i++) {
                    data.add((int) inode.getAddress()[i]);
                }
                index.add((int) inode.getAddress()[12]);
                ArrayList<Integer> list = jsonDataOperate.jsonFileParse(new ArrayList<Integer>(), inode.getAddress()[12] + "");
                for (int i = 0; i < list.size(); i++) {
                    data.add(list.get(i));
                }
                map.put("data",data);
                map.put("index",index);
            }
            else if(kb<=524)//直接索引x11+一级索引x2
            {
                for (int i = 0; i < 11; i++) {
                    data.add((int) inode.getAddress()[i]);
                }
                index.add((int) inode.getAddress()[11]);
                index.add((int) inode.getAddress()[12]);
                ArrayList<Integer> list = jsonDataOperate.jsonFileParse(new ArrayList<Integer>(), inode.getAddress()[11] + "");
                ArrayList<Integer> list2 = jsonDataOperate.jsonFileParse(new ArrayList<Integer>(), inode.getAddress()[12] + "");
                for (int i = 0; i < list.size(); i++) {
                    data.add(list.get(i));
                }
                for (int i = 0; i < list2.size(); i++) {
                    data.add(list2.get(i));
                }
                map.put("data",data);
                map.put("index",index);
            }
            else if(kb<=65548)//直接索引x12+二级索引x1   64mb+12kb
            {
                for (int i = 0; i < 12; i++) {
                    data.add((int) inode.getAddress()[i]);
                }
                index.add((int) inode.getAddress()[12]);
                ArrayList<Integer> SecondaryList = jsonDataOperate.jsonFileParse(new ArrayList<Integer>(), inode.getAddress()[12] + "");
                for (int i = 0; i <SecondaryList.size(); i++) {
                    index.add(SecondaryList.get(i));
                    ArrayList<Integer> FirstList = jsonDataOperate.jsonFileParse(new ArrayList<Integer>(), SecondaryList.get(i) + "");
                    for (int i1 = 0; i1 < FirstList.size(); i1++) {
                        data.add(FirstList.get(i1));
                    }
                }
                map.put("data",data);
                map.put("index",index);
            }
        }
        else if(inode.getType()==1)//目录文本
        {
            if(inode==globalVariable.rootInode)//根节点
            {
                LinkedList<Integer> integers = new LinkedList<>();
                for (int i = globalVariable.foundation.rootDirBlockStart; i < globalVariable.foundation.rootDirBlockStart+globalVariable.foundation.rootDirBlockCount; i++) {
                    integers.add(i);
                }
                map.put("index",integers);
            }
            else{
                LinkedList<Integer> integers = new LinkedList<>();
                for (int i = 0; i < 4; i++) {
                    integers.add((int) inode.getAddress()[i]);
                }
                map.put("index",integers);
            }
        }
        return map;
    }
    /**
    * @Description 创建索引(直接索引和一级索引和二级索引
    * @Author  lenovo
    * @Date   2023/12/17 16:57
    * @Param
    * @Return
    * @Exception
    */

    public INode createIndex(Long B) {
        INode inode = new INode((byte) 0);
        int kb = (int) Math.ceil(B*1.0 / 1024);
        if (kb <= 13) {
            ArrayList<Integer> blocksArray = freeBlockLinkedListOperate.allocateBlock(B);
            short[] shorts = new short[13];
            for (int i = 0; i < blocksArray.size(); i++) {
                shorts[i] = (short) (int) blocksArray.get(i);
            }
            inode.setAddress(shorts);
            return inode;
        } else if (kb <= 268)//直接索引x12+一级索引x1
        {
            int i = 0;
            B = B + 1024;
            ArrayList<Integer> blocksArray = freeBlockLinkedListOperate.allocateBlock(B);
            short[] shorts = new short[13];

            for (; i < 13; i++) {
                shorts[i] = (short) (int) blocksArray.get(i);
            }
            //12为一级索引
            jsonDataOperate.jsonFileStringify(blocksArray.subList(i, blocksArray.size()), new String[]{shorts[12] + ""});
            inode.setAddress(shorts);
            return inode;
        } else if (kb <= 524)//直接索引x11+一级索引x2
        {
            int i = 0;
            B = B + 1024 * 2;
            ArrayList<Integer> blocksArray = freeBlockLinkedListOperate.allocateBlock(B);
            short[] shorts = new short[13];

            for (; i < 13; i++) {
                shorts[i] = (short) (int) blocksArray.get(i);
            }
            //12为一级索引
            jsonDataOperate.jsonFileStringify(blocksArray.subList(i, i + 256), new String[]{shorts[11] + ""});
            jsonDataOperate.jsonFileStringify(blocksArray.subList(i + 256, blocksArray.size()), new String[]{shorts[12] + ""});
            inode.setAddress(shorts);
            return inode;
        } else if (kb <= 65548)//直接索引x12+二级索引x1   64mb+12kb
        {
            if(kb>globalVariable.superBlock.singeFileMaxSize)
            {
                System.err.println("超出文件最大范围了");
                error.setError(error.OutOfSingleFileMaxSizeError);
                return null;
            }
            kb -= 12;
            int firstIndex = (int) Math.ceil(kb*1.0 / 256);
            firstIndex++;//二级索引也要占一个物理块
            B = B + 1024 * firstIndex;
            int i = 0;



            ArrayList<Integer> blocksArray = freeBlockLinkedListOperate.allocateBlock(B);
            if(blocksArray==null){
                error.setError(error.OutOfMemoryError);

                return null;
            }


            short[] shorts = new short[13];

            for (; i < 13; i++) {
                shorts[i] = (short) (int) blocksArray.get(i);
            }
            firstIndex--;//把二级索引占的物理块去掉
            //12为二级索引
            ArrayList<Integer> SecondaryIndex = new ArrayList<>();
            while (firstIndex != 0) {
                if (firstIndex != 1)
                    jsonDataOperate.jsonFileStringify(blocksArray.subList(i+1 , i + 257), new String[]{blocksArray.get(i) + ""});

                else {
                    jsonDataOperate.jsonFileStringify(blocksArray.subList(i + 1, blocksArray.size()), new String[]{blocksArray.get(i) + ""});
                }
                SecondaryIndex.add(blocksArray.get(i));
                i += 257;
                firstIndex--;
            }
            jsonDataOperate.jsonFileStringify(SecondaryIndex, new String[]{shorts[12] + ""});
            inode.setAddress(shorts);
            return inode;
        }
        return null;
    }
}
